{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1dc-6G5q_ydz"
      },
      "source": [
        "# SD WebUI All In One Colab\n",
        "#### Created by [licyk](https://github.com/licyk)\n",
        "\n",
        "Jupyter Notebook 仓库：[licyk/sd-webui-all-in-one](https://github.com/licyk/sd-webui-all-in-one)\n",
        "\n",
        "这是一个支持部署多种 WebUI 的 Jupyter Notebook，支持部署以下 WebUI：\n",
        "- 1、[InvokeAI](https://github.com/invoke-ai/InvokeAI)\n",
        "- 2、[Fooocus](https://github.com/lllyasviel/Fooocus)\n",
        "- 3、[lora-scripts](https://github.com/Akegarasu/lora-scripts)\n",
        "- 4、[kohya_ss](https://github.com/bmaltais/kohya_ss)\n",
        "\n",
        "使用时请按顺序执行 Jupyter Notebook 单元。\n",
        "\n",
        "## 主要功能\n",
        "1. 功能初始化：导入 SD WebUI All In One 所使用的功能\n",
        "2. 参数配置：配置安装参数、远程访问方式、模型 / 扩展选择（有以下选项：Stable Diffusion 模型、LoRA 模型、Embedding 模型、VAE 模型、VAE-approx 模型、放大模型、ControlNet 模型、SD WebUI 扩展、ComfyUI 扩展）。\n",
        "3. 应用参数配置：应用已设置的参数\n",
        "4. 安装：根据配置安装对应的 WebUI\n",
        "5. 启动：根据配置启动对应的 WebUI\n",
        "\n",
        "## 其他功能\n",
        "1. 自定义模型 / 扩展下载配置：设置要下载的模型 / 扩展参数\n",
        "2. 自定义模型 / 扩展下载：根据配置进行下载模型 / 扩展\n",
        "3. 更新：将已安装的 WebUI 进行更新\n",
        "\n",
        "## 提示\n",
        "1. 在参数配置界面，请填写工作区路径（根据使用的平台进行填写，如Kaggle 平台填写`/kaggle`，Colab 平台填写`/content`），选择要使用的 WebUI，根据自己的需求选择内网穿透方式（用于访问 WebUI 界面），再根据自己的需求选择模型和扩展。\n",
        "2. 已知 CloudFlare、Gradio 内网穿透会导致 [Kaggle](https://www.kaggle.com) 平台强制关机，在使用 [Kaggle](https://www.kaggle.com) 平台时请勿勾选这两个选项。\n",
        "3. 若使用 [Colab](https://colab.research.google.com) 平台，请注意该 Jupyter Notebook 无法在免费版的 Colab 账号中使用，运行前将会收到 Colab 的警告提示，强行运行将会导致 Colab 强制关机（如果 Colab 账号已付费订阅可直接使用该 Jupyter Notebook），可选择仓库中其他的  Jupyter Notebook（将 Colab 中禁止的 WebUI 移除了）。\n",
        "4. [Ngrok](https://ngrok.com) 内网穿透的稳定性高，使用前需要填写 Ngrok Token，可在 [Ngrok](https://ngrok.com) 官网获取。\n",
        "5. 在启动时将启动内网穿透，可在控制台输出中看到内网穿透地址，用于访问 WebUI 界面。\n",
        "6. 云平台可能存在 ipywidgets 显示 Bug 导致一些提示无法显示出来，主要在参数配置单元的模型 / 扩展选择中出现这种问题。\n",
        "7. 调整参数配置后必须运行一次应用参数配置。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "REpDxeFzBH-T",
        "outputId": "bec4e2e4-c059-45a6-ee0e-668eebbcf9c3"
      },
      "outputs": [],
      "source": [
        "#@title 👇 功能初始化\n",
        "INIT_CONFIG = 1\n",
        "\n",
        "# 消息格式输出\n",
        "def echo(*args):\n",
        "    for i in args:\n",
        "        print(f\":: {i}\")\n",
        "\n",
        "\n",
        "\n",
        "# ARIA2\n",
        "class ARIA2:\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    # 下载器\n",
        "    def aria2(self, url, path, filename):\n",
        "        import os\n",
        "        if not os.path.exists(path + \"/\" + filename):\n",
        "            echo(f\"开始下载 {filename} ，路径: {path}/{filename}\")\n",
        "            !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M \"{url}\" -d \"{path}\" -o \"{filename}\"\n",
        "            if os.path.exists(path + \"/\" + filename) and not os.path.exists(path + \"/\" + filename + \".aria2\"):\n",
        "                echo(f\"{filename} 下载完成\")\n",
        "            else:\n",
        "                echo(f\"{filename} 下载中断\")\n",
        "        else:\n",
        "            if os.path.exists(path + \"/\" + filename + \".aria2\"):\n",
        "                echo(f\"开始下载 {filename} ，路径: {path}/{filename}\")\n",
        "                !aria2c --console-log-level=error -c -x 16 -s 16 -k 1M \"{url}\" -d \"{path}\" -o \"{filename}\"\n",
        "                if os.path.exists(path + \"/\" + filename) and not os.path.exists(path + \"/\" + filename + \".aria2\"):\n",
        "                    echo(f\"{filename} 下载完成\")\n",
        "                else:\n",
        "                    echo(f\"{filename} 下载中断\")\n",
        "            else:\n",
        "                echo(f\"{filename} 文件已存在，路径: {path}/{filename}\")\n",
        "\n",
        "\n",
        "    # 大模型下载\n",
        "    def get_sd_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # lora下载\n",
        "    def get_lora_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # 放大模型下载\n",
        "    def get_upscale_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # embedding模型下载\n",
        "    def get_embedding_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # controlnet模型下载\n",
        "    def get_controlnet_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # vae模型下载\n",
        "    def get_vae_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # vae-approx模型下载\n",
        "    def get_vae_approx_model(self, url, filename):\n",
        "        pass\n",
        "\n",
        "\n",
        "    # 获取modelscope下载链接\n",
        "    def get_modelscope_link(self, origin):\n",
        "        user = origin.split(\"/\")[0]\n",
        "        repo = origin.split(\"/\")[1]\n",
        "        branch = origin.split(\"/\")[2]\n",
        "        tmp = f\"{user}/{repo}/{branch}/\"\n",
        "        file = origin.split(tmp).pop().replace(\"/\", \"%2F\")\n",
        "        link = f\"https://modelscope.cn/api/v1/models/{user}/{repo}/repo?Revision={branch}&FilePath={file}\"\n",
        "        return link\n",
        "\n",
        "\n",
        "\n",
        "# GIT\n",
        "class GIT:\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    # 检测要克隆的项目是否存在于指定路径\n",
        "    def exists(self, addr=None, path=None, name=None):\n",
        "        import os\n",
        "        if addr is not None:\n",
        "            if path is None and name is None:\n",
        "                path = os.getcwd() + \"/\" + addr.split(\"/\").pop().split(\".git\", 1)[0]\n",
        "            elif path is None and name is not None:\n",
        "                path = os.getcwd() + \"/\" + name\n",
        "            elif path is not None and name is None:\n",
        "                path = os.path.normpath(path) + \"/\" + addr.split(\"/\").pop().split(\".git\", 1)[0]\n",
        "\n",
        "        if os.path.exists(path):\n",
        "            return True\n",
        "        else:\n",
        "            return False\n",
        "\n",
        "\n",
        "    # 克隆项目\n",
        "    def clone(self, addr, path=None, name=None):\n",
        "        import os\n",
        "        repo = addr.split(\"/\").pop().split(\".git\", 1)[0]\n",
        "        if not self.exists(addr, path, name):\n",
        "            echo(f\"开始下载 {repo}\")\n",
        "            if path is None and name is None:\n",
        "                path = os.getcwd()\n",
        "                name = repo\n",
        "            elif path is not None and name is None:\n",
        "                name = repo\n",
        "            elif path is None and name is not None:\n",
        "                path = os.getcwd()\n",
        "            !git clone {addr} \"{path}/{name}\" --recurse-submodules\n",
        "        else:\n",
        "            echo(f\"{repo} 已存在\")\n",
        "\n",
        "\n",
        "    # 拉取更新\n",
        "    def pull(self, path):\n",
        "        import os\n",
        "        if self.exists(path=path) and self.exists(path + \"/.git\"):\n",
        "            repo = os.path.normpath(path).split(\"/\" and \"\\\\\").pop()\n",
        "            echo(f\"更新 {repo} 中\")\n",
        "            if self.is_git_pointer_offset(path=path):\n",
        "                self.fix_pointer(path=path)\n",
        "            !git -C \"{path}\" pull --recurse-submodules\n",
        "        else:\n",
        "            echo(f\"路径不存在\")\n",
        "\n",
        "\n",
        "    # 切换到指定版本\n",
        "    def checkout(self, path, commit=None):\n",
        "        import os\n",
        "        if self.exists(path=path) and self.exists(path + \"/.git\"):\n",
        "            repo = os.path.normpath(path).split(\"/\" and \"\\\\\").pop()\n",
        "            if commit is not None:\n",
        "                echo(f\"切换 {repo} 版本中\")\n",
        "                !git -C \"{path}\" reset --hard {commit} --recurse-submodules\n",
        "            else:\n",
        "                echo(f\"未指定 {repo} 版本\")\n",
        "        else:\n",
        "            echo(\"路径不存在\")\n",
        "\n",
        "\n",
        "    # 修复分支漂移\n",
        "    def fix_pointer(self, path):\n",
        "        import os\n",
        "        import subprocess\n",
        "        if self.exists(path=path):\n",
        "            repo = os.path.normpath(path).split(\"/\" and \"\\\\\").pop()\n",
        "            echo(f\"修复 {repo} 分支游离中\")\n",
        "            !git -C \"{path}\" remote prune origin\n",
        "            !git -C \"{path}\" submodule init\n",
        "            result = subprocess.run(f\"git -C \\\"{path}\\\" branch -a | grep /HEAD\", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout\n",
        "            print(result)\n",
        "            branch = result.split(\"/\").pop()\n",
        "            !git -C \"{path}\" checkout {branch} # 切换到主分支\n",
        "            !git -C \"{path}\" reset --recurse-submodules --hard origin/{branch}\n",
        "            !git -C \"{path}\" reset --recurse-submodules --hard HEAD\n",
        "            !git -C \"{path}\" restore --recurse-submodules --source=HEAD :/\n",
        "        else:\n",
        "            echo(\"路径不存在\")\n",
        "\n",
        "\n",
        "    # 检测分支是否漂移\n",
        "    def is_git_pointer_offset(self, path):\n",
        "        if self.exists(path=path):\n",
        "            import subprocess\n",
        "            result = subprocess.run(f\"git -C \\\"{path}\\\" symbolic-ref HEAD\", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).returncode\n",
        "            if result == 0:\n",
        "                return True\n",
        "            else:\n",
        "                echo(\"检测到出现分支游离\")\n",
        "                return False\n",
        "\n",
        "\n",
        "    # 输出版本信息\n",
        "    def git_show_ver(self, path):\n",
        "        import subprocess\n",
        "        if self.exists(path=path) and self.exists(path + \"/.git\"):\n",
        "            result = subprocess.run(f\"git -C \\\"{path}\\\" symbolic-ref HEAD\", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).returncode\n",
        "            if result == 0:\n",
        "                cmd1 = f\"git -C \\\"{path}\\\" rev-parse --short HEAD\"\n",
        "                cmd2 = f\"git -C \\\"{path}\\\" show -s --format=\\\"%cd\\\" --date=format:\\\"%Y-%m-%d %H:%M:%S\\\"\"\n",
        "                commit = subprocess.run(f\"git -C \\\"{path}\\\" symbolic-ref HEAD\", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout.replace(\"refs/heads/\", \"\").replace(\"\\n\",\"\")\n",
        "                commit = commit + \" \"  + subprocess.run(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout.replace(\"\\n\",\"\")\n",
        "                commit = commit + \" \"  + subprocess.run(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout.replace(\"\\n\",\"\")\n",
        "            else:\n",
        "                cmd1 = f\"git -C \\\"{path}\\\" rev-parse --short HEAD\"\n",
        "                cmd2 = f\"git -C \\\"{path}\\\" show -s --format=\\\"%cd\\\" --date=format:\\\"%Y-%m-%d %H:%M:%S\\\"\"\n",
        "                commit = subprocess.run(cmd1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout.replace(\"\\n\",\"\")\n",
        "                commit = commit + \" \"  + subprocess.run(cmd2, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout.replace(\"\\n\",\"\")\n",
        "                commit = commit + \" (分支游离)\"\n",
        "            return path.split(\"/\").pop() + \": \" + commit\n",
        "        else:\n",
        "            return \"(非 Git 安装)\"\n",
        "\n",
        "\n",
        "    def log(self, path):\n",
        "        import subprocess\n",
        "        if self.exists(path=path) and self.exists(path + \"/.git\"):\n",
        "            result = subprocess.run(f\"git -C \\\"{path}\\\" symbolic-ref HEAD\", stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).returncode\n",
        "            if result == 0:\n",
        "                cmd = f\"git -C \\\"{path}\\\" log --all --date=short --pretty=format:\\\"%h %cd\\\" --date=format:\\\"%Y-%m-%d | %H:%M:%S\\\"\"\n",
        "            return path.split(\"/\").pop() + \" 版本信息: \\n\" + subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, shell=True).stdout\n",
        "        else:\n",
        "            return path.split(\"/\").pop() + \" 非 Git 安装\"\n",
        "\n",
        "\n",
        "    def test_github_mirror(self, mirror):\n",
        "        import os\n",
        "        import subprocess\n",
        "        path = self.WORKSPACE + \"/empty\"\n",
        "        for i in mirror:\n",
        "            test_repo = i.replace(\"term_sd_git_user/term_sd_git_repo\",\"licyk/empty\")\n",
        "            avaliable_mirror = i.replace(\"/term_sd_git_user/term_sd_git_repo\",\"\")\n",
        "            mirror_url = i.replace(\"term_sd_git_user/term_sd_git_repo\",\"\")\n",
        "            echo(f\"测试 Github 镜像源: {mirror_url}\")\n",
        "            if os.path.exists(path):\n",
        "                !rm -rf \"{path}\"\n",
        "            result = subprocess.run(f\"git clone {test_repo} {path}\")\n",
        "            if os.path.exists(path):\n",
        "                !rm -rf \"{path}\"\n",
        "            if result.returncode == 0:\n",
        "                return avaliable_mirror\n",
        "        return False\n",
        "\n",
        "\n",
        "    def set_github_mirror(self, mirror):\n",
        "        import os\n",
        "        avaliable_mirror = self.test_github_mirror(mirror)\n",
        "        git_config_path = self.WORKSPACE + \"/.gitconfig\"\n",
        "        if avaliable_mirror is not False:\n",
        "            echo(f\"设置 GIthub 镜像源: {avaliable_mirror}\")\n",
        "            if os.path.exists(git_config_path):\n",
        "                !rm -rf \"{git_config_path}\"\n",
        "            os.environ[\"GIT_CONFIG_GLOBAL\"] = git_config_path\n",
        "            !git config --global url.{avaliable_mirror}.insteadOf https://github.com\n",
        "        else:\n",
        "            echo(\"未找到可用 Github 镜像源, 取消设置 GIthub 镜像源\")\n",
        "\n",
        "\n",
        "    def unset_github_mirror(self):\n",
        "        import os\n",
        "        if \"GIT_CONFIG_GLOBAL\" in os.environ:\n",
        "            echo(\"删除 Github 镜像源配置\")\n",
        "            os.unsetenv(\"GIT_CONFIG_GLOBAL\")\n",
        "        else:\n",
        "            echo(\"Github 镜像源未设置, 无需删除\")\n",
        "\n",
        "\n",
        "\n",
        "# TUNNEL\n",
        "class TUNNEL:\n",
        "    LOCALHOST_RUN = \"localhost.run\"\n",
        "    REMOTE_MOE = \"remote.moe\"\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "    PORT = \"\"\n",
        "\n",
        "\n",
        "    def __init__(self, workspace, workfolder, port) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "        self.PORT = port\n",
        "\n",
        "\n",
        "    # ngrok内网穿透\n",
        "    def ngrok(self, ngrok_token: str):\n",
        "        from pyngrok import conf, ngrok\n",
        "        conf.get_default().auth_token = ngrok_token\n",
        "        conf.get_default().monitor_thread = False\n",
        "        port = self.PORT\n",
        "        ssh_tunnels = ngrok.get_tunnels(conf.get_default())\n",
        "        if len(ssh_tunnels) == 0:\n",
        "            ssh_tunnel = ngrok.connect(port, bind_tls=True)\n",
        "            return ssh_tunnel.public_url\n",
        "        else:\n",
        "            return ssh_tunnels[0].public_url\n",
        "\n",
        "\n",
        "    # cloudflare内网穿透\n",
        "    def cloudflare(self):\n",
        "        from pycloudflared import try_cloudflare\n",
        "        port = self.PORT\n",
        "        urls = try_cloudflare(port).tunnel\n",
        "        return urls\n",
        "\n",
        "\n",
        "    from typing import Union\n",
        "    from pathlib import Path\n",
        "\n",
        "    # 生成ssh密钥\n",
        "    def gen_key(self, path: Union[str, Path]) -> None:\n",
        "        import subprocess\n",
        "        import shlex\n",
        "        from pathlib import Path\n",
        "        path = Path(path)\n",
        "        arg_string = f'ssh-keygen -t rsa -b 4096 -N \"\" -q -f {path.as_posix()}'\n",
        "        args = shlex.split(arg_string)\n",
        "        subprocess.run(args, check=True)\n",
        "        path.chmod(0o600)\n",
        "\n",
        "\n",
        "    # ssh内网穿透\n",
        "    def ssh_tunnel(self, host: str) -> None:\n",
        "        import subprocess\n",
        "        import atexit\n",
        "        import shlex\n",
        "        import re\n",
        "        import os\n",
        "        from pathlib import Path\n",
        "        from tempfile import TemporaryDirectory\n",
        "\n",
        "        ssh_name = \"id_rsa\"\n",
        "        ssh_path = Path(self.WORKSPACE) / ssh_name\n",
        "        port = self.PORT\n",
        "\n",
        "        tmp = None\n",
        "        if not ssh_path.exists():\n",
        "            try:\n",
        "                self.gen_key(ssh_path)\n",
        "            # write permission error or etc\n",
        "            except subprocess.CalledProcessError:\n",
        "                tmp = TemporaryDirectory()\n",
        "                ssh_path = Path(tmp.name) / ssh_name\n",
        "                self.gen_key(ssh_path)\n",
        "\n",
        "        arg_string = f\"ssh -R 80:127.0.0.1:{port} -o StrictHostKeyChecking=no -i {ssh_path.as_posix()} {host}\"\n",
        "        args = shlex.split(arg_string)\n",
        "\n",
        "        tunnel = subprocess.Popen(\n",
        "            args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding=\"utf-8\"\n",
        "        )\n",
        "\n",
        "        atexit.register(tunnel.terminate)\n",
        "        if tmp is not None:\n",
        "            atexit.register(tmp.cleanup)\n",
        "\n",
        "        tunnel_url = \"\"\n",
        "        LOCALHOST_RUN = self.LOCALHOST_RUN\n",
        "        lines = 27 if host == LOCALHOST_RUN else 5\n",
        "        localhostrun_pattern = re.compile(r\"(?P<url>https?://\\S+\\.lhr\\.life)\")\n",
        "        remotemoe_pattern = re.compile(r\"(?P<url>https?://\\S+\\.remote\\.moe)\")\n",
        "        pattern = localhostrun_pattern if host == LOCALHOST_RUN else remotemoe_pattern\n",
        "\n",
        "        for _ in range(lines):\n",
        "            line = tunnel.stdout.readline()\n",
        "            if line.startswith(\"Warning\"):\n",
        "                print(line, end=\"\")\n",
        "\n",
        "            url_match = pattern.search(line)\n",
        "            if url_match:\n",
        "                tunnel_url = url_match.group(\"url\")\n",
        "                if lines == 27:\n",
        "                    os.environ['LOCALHOST_RUN'] = tunnel_url\n",
        "                    return tunnel_url\n",
        "                else:\n",
        "                    os.environ['REMOTE_MOE'] = tunnel_url\n",
        "                    return tunnel_url\n",
        "                # break\n",
        "        else:\n",
        "            echo(f\"启动 {host} 内网穿透失败\")\n",
        "\n",
        "\n",
        "    # localhost.run穿透\n",
        "    def localhost_run(self):\n",
        "        urls = self.ssh_tunnel(self.LOCALHOST_RUN)\n",
        "        return urls\n",
        "\n",
        "\n",
        "    # remote.moe内网穿透\n",
        "    def remote_moe(self):\n",
        "        urls = self.ssh_tunnel(self.REMOTE_MOE)\n",
        "        return urls\n",
        "\n",
        "\n",
        "    # gradio内网穿透\n",
        "    def gradio(self):\n",
        "        import subprocess\n",
        "        import shlex\n",
        "        import atexit\n",
        "        import re\n",
        "        port = self.PORT\n",
        "        cmd = f\"gradio-tunneling --port {port}\"\n",
        "        cmd = shlex.split(cmd)\n",
        "        tunnel = subprocess.Popen(\n",
        "            cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding=\"utf-8\"\n",
        "        )\n",
        "\n",
        "        atexit.register(tunnel.terminate)\n",
        "\n",
        "        tunnel_url = \"\"\n",
        "        lines = 5\n",
        "        gradio_pattern = re.compile(r\"(?P<url>https?://\\S+\\.gradio\\.live)\")\n",
        "        pattern = gradio_pattern\n",
        "\n",
        "        for _ in range(lines):\n",
        "            line = tunnel.stdout.readline()\n",
        "            if line.startswith(\"Warning\"):\n",
        "                print(line, end=\"\")\n",
        "            url_match = pattern.search(line)\n",
        "            if url_match:\n",
        "                tunnel_url = url_match.group(\"url\")\n",
        "                return tunnel_url\n",
        "        else:\n",
        "            echo(f\"启动 Gradio 内网穿透失败\")\n",
        "\n",
        "\n",
        "    # 启动内网穿透\n",
        "    def start(self, ngrok=False, ngrok_token=None, cloudflare=False, remote_moe=False, localhost_run=False, gradio=False):\n",
        "        if cloudflare is True or ngrok is True or ngrok_token is not None or remote_moe is True or localhost_run is True or gradio is True:\n",
        "            echo(\"启动内网穿透\")\n",
        "\n",
        "        if cloudflare is True:\n",
        "            cloudflare_url = self.cloudflare()\n",
        "        else:\n",
        "            cloudflare_url = None\n",
        "\n",
        "        if ngrok is True and ngrok_token is not None:\n",
        "            ngrok_url = self.ngrok(ngrok_token)\n",
        "        else:\n",
        "            ngrok_url = None\n",
        "\n",
        "        if remote_moe is True:\n",
        "            remote_moe_url = self.remote_moe()\n",
        "        else:\n",
        "            remote_moe_url = None\n",
        "\n",
        "        if localhost_run is True:\n",
        "            localhost_run_url = self.localhost_run()\n",
        "        else:\n",
        "            localhost_run_url = None\n",
        "\n",
        "        if gradio is True:\n",
        "            gradio_url = self.gradio()\n",
        "        else:\n",
        "            gradio_url = None\n",
        "\n",
        "        echo(\"下方为访问地址\")\n",
        "        print(\"==================================================================================\")\n",
        "        echo(f\"CloudFlare: {cloudflare_url}\")\n",
        "        echo(f\"Ngrok: {ngrok_url}\")\n",
        "        echo(f\"remote.moe: {remote_moe_url}\")\n",
        "        echo(f\"localhost_run: {localhost_run_url}\")\n",
        "        echo(f\"Gradio: {gradio_url}\")\n",
        "        print(\"==================================================================================\")\n",
        "\n",
        "\n",
        "\n",
        "# ENV\n",
        "class ENV:\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    # 准备ipynb笔记自身功能的依赖\n",
        "    def prepare_env_depend(self, use_mirror=True):\n",
        "        if use_mirror is True:\n",
        "            pip_mirror = \"--index-url https://mirrors.cloud.tencent.com/pypi/simple --find-links https://mirror.sjtu.edu.cn/pytorch-wheels/cu121/torch_stable.html\"\n",
        "        else:\n",
        "            pip_mirror = \"--index-url https://pypi.python.org/simple --find-links https://download.pytorch.org/whl/cu121/torch_stable.html\"\n",
        "\n",
        "        echo(\"安装自身组件依赖\")\n",
        "        !pip install pyngrok pycloudflared gradio-tunneling {pip_mirror}\n",
        "        !apt update\n",
        "        !apt install aria2 ssh google-perftools -y\n",
        "\n",
        "\n",
        "    # 安装pytorch和xformers\n",
        "    def prepare_torch(self, torch_ver, xformers_ver, use_mirror=False):\n",
        "        arg = \"--no-deps\"\n",
        "        if use_mirror is True:\n",
        "            pip_mirror = \"--index-url https://mirrors.cloud.tencent.com/pypi/simple --find-links https://mirror.sjtu.edu.cn/pytorch-wheels/cu121/torch_stable.html\"\n",
        "        else:\n",
        "            pip_mirror = \"--index-url https://pypi.python.org/simple --find-links https://download.pytorch.org/whl/cu121/torch_stable.html\"\n",
        "        \n",
        "        if torch_ver != \"\":\n",
        "            echo(\"安装 PyTorch\")\n",
        "            !pip install {torch_ver} {pip_mirror}\n",
        "        if xformers_ver != \"\":\n",
        "            echo(\"安装 xFormers\")\n",
        "            !pip install {xformers_ver} {pip_mirror} {arg}\n",
        "\n",
        "\n",
        "    # 安装requirements.txt依赖\n",
        "    def install_requirements(self, path, use_mirror=False):\n",
        "        import os\n",
        "        if use_mirror is True:\n",
        "            pip_mirror = \"--index-url https://mirrors.cloud.tencent.com/pypi/simple --find-links https://mirror.sjtu.edu.cn/pytorch-wheels/cu121/torch_stable.html\"\n",
        "        else:\n",
        "            pip_mirror = \"--index-url https://pypi.python.org/simple --find-links https://download.pytorch.org/whl/cu121/torch_stable.html\"\n",
        "        if os.path.exists(path):\n",
        "            echo(\"安装依赖\")\n",
        "            !pip install -r \"{path}\" {pip_mirror}\n",
        "        else:\n",
        "            echo(\"依赖文件路径为空\")\n",
        "\n",
        "\n",
        "    # python软件包安装\n",
        "    # 可使用的操作:\n",
        "    # 安装: install -> install\n",
        "    # 仅安装: install_single -> install --no-deps\n",
        "    # 强制重装: force_install -> install --force-reinstall\n",
        "    # 仅强制重装: force_install_single -> install --force-reinstall --no-deps\n",
        "    # 更新: update -> install --upgrade\n",
        "    # 卸载: uninstall -y\n",
        "    def py_pkg_manager(self, pkg, type=None, use_mirror=False):\n",
        "        if use_mirror is True:\n",
        "            pip_mirror = \"--index-url https://mirrors.cloud.tencent.com/pypi/simple --find-links https://mirror.sjtu.edu.cn/pytorch-wheels/cu121/torch_stable.html\"\n",
        "        else:\n",
        "            pip_mirror = \"--index-url https://pypi.python.org/simple --find-links https://download.pytorch.org/whl/cu121/torch_stable.html\"\n",
        "\n",
        "        if type == \"install\":\n",
        "            func = \"install\"\n",
        "            args = \"\"\n",
        "        elif type == \"install_single\":\n",
        "            func = \"install\"\n",
        "            args = \"--no-deps\"\n",
        "        elif type == \"force_install\":\n",
        "            func = \"install\"\n",
        "            args = \"--force-reinstall\"\n",
        "        elif type == \"force_install_single\":\n",
        "            func = \"install\"\n",
        "            args = \"install --force-reinstall --no-deps\"\n",
        "        elif type == \"update\":\n",
        "            func = \"install\"\n",
        "            args = \"--upgrade\"\n",
        "        elif type == \"uninstall\":\n",
        "            func = \"uninstall\"\n",
        "            args = \"-y\"\n",
        "            pip_mirror = \"\"\n",
        "        else:\n",
        "            echo(f\"未知操作: {type}\")\n",
        "            return\n",
        "        echo(f\"执行操作: pip {func} {pkg} {args} {pip_mirror}\")\n",
        "        !pip {func} {pkg} {args} {pip_mirror}\n",
        "\n",
        "\n",
        "    # 配置内存优化\n",
        "    def tcmalloc(self):\n",
        "        echo(\"配置内存优化\")\n",
        "        import os\n",
        "        os.environ[\"LD_PRELOAD\"] = \"/usr/lib/x86_64-linux-gnu/libtcmalloc_minimal.so.4\"\n",
        "\n",
        "\n",
        "    # 适用于colab的内存优化\n",
        "    def tcmalloc_colab(self):\n",
        "        echo(\"配置内存优化\")\n",
        "        import os\n",
        "        aria2 = ARIA2(self.WORKSPACE, self.WORKFOLDER)\n",
        "        path = self.WORKSPACE\n",
        "        libtcmalloc_path = self.WORKSPACE + \"/libtcmalloc_minimal.so.4\"\n",
        "        aria2.aria2(\"https://github.com/licyk/term-sd/releases/download/archive/libtcmalloc_minimal.so.4\", path, \"libtcmalloc_minimal.so.4\")\n",
        "        os.environ[\"LD_PRELOAD\"] = libtcmalloc_path\n",
        "\n",
        "\n",
        "\n",
        "# MANAGER\n",
        "class MANAGER:\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    # 清理ipynb笔记的输出\n",
        "    def clear_up(self, opt):\n",
        "        from IPython.display import clear_output\n",
        "        clear_output(wait=opt)\n",
        "\n",
        "\n",
        "    # 检查gpu是否可用\n",
        "    def check_gpu(self):\n",
        "        echo(\"检测 GPU 是否可用\")\n",
        "        import tensorflow as tf\n",
        "        echo(f\"TensorFlow 版本: {tf.__version__}\")\n",
        "        if tf.test.gpu_device_name():\n",
        "            echo(\"GPU 可用\")\n",
        "        else:\n",
        "            echo(\"GPU 不可用\")\n",
        "            raise Exception(\"\\n没有使用GPU，请在代码执行程序-更改运行时类型-设置为GPU！\\n如果不能使用GPU，建议更换账号！\")\n",
        "\n",
        "\n",
        "    # 配置google drive\n",
        "    def config_google_drive(self):\n",
        "        echo(\"挂载 Google Drive\")\n",
        "        import os\n",
        "        if not os.path.exists('/content/drive/MyDrive'):\n",
        "            from google.colab import drive\n",
        "            drive.mount('/content/drive')\n",
        "            echo(\"Google Dirve 挂载完成\")\n",
        "        else:\n",
        "            echo(\"Google Drive 已挂载\")\n",
        "\n",
        "        # 检测并创建输出文件夹\n",
        "        if os.path.exists('/content/drive/MyDrive'):\n",
        "            if not os.path.exists('/content/drive/MyDrive/fooocus_output'):\n",
        "                echo(\"在 Google Drive 创建 fooocus_ouput 文件夹\")\n",
        "                !mkdir -p /content/drive/MyDrive/fooocus_output\n",
        "        else:\n",
        "            raise Exception(\"未挂载 Google Drive，请重新挂载后重试！\")\n",
        "\n",
        "\n",
        "    def set_huggingface_mirror(self ,mirror):\n",
        "        import os\n",
        "        echo(f\"设置 HuggingFace 镜像源: {mirror}\")\n",
        "        os.environ[\"HF_ENDPOINT\"] = mirror\n",
        "\n",
        "\n",
        "    def unset_huggingface_mirror(self):\n",
        "        import os\n",
        "        if \"HF_ENDPOINT\" in os.environ:\n",
        "            echo(\"删除 HuggingFace 镜像源配置\")\n",
        "            os.unsetenv(\"HF_ENDPOINT\")\n",
        "        else:\n",
        "            echo(\"HuggingFace 镜像源未设置, 无需删除\")\n",
        "\n",
        "\n",
        "    def hf_link_to_mirror_link(self, hf_mirror, url):\n",
        "        if isinstance(url, str):\n",
        "            return url.replace(\"https://huggingface.co\",hf_mirror)\n",
        "        else:\n",
        "            mirror_url = url\n",
        "            j = 0\n",
        "            for i in mirror_url:\n",
        "                tmp = i.replace(\"https://huggingface.co\",hf_mirror)\n",
        "                mirror_url[j] = tmp\n",
        "                j += 1\n",
        "            return mirror_url\n",
        "\n",
        "\n",
        "    def select_list(self, data, name):\n",
        "        # https://stackoverflow.com/questions/57219796/ipywidgets-dynamic-creation-of-checkboxes-and-selection-of-data\n",
        "        # https://gist.github.com/MattJBritton/9dc26109acb4dfe17820cf72d82f1e6f\n",
        "        import ipywidgets as widgets\n",
        "        names = [] # 可选择的列表\n",
        "        checkbox_objects = [] # 按钮对象\n",
        "        for key in data:\n",
        "            value = key[1]\n",
        "            key = key[0].split(\"/\").pop()\n",
        "            if value == 1:\n",
        "                select = True\n",
        "            else:\n",
        "                select = False\n",
        "            checkbox_objects.append(widgets.Checkbox(value=select, description=key, )) # 扩展按钮列表\n",
        "            names.append(key)\n",
        "\n",
        "        arg_dict = {names[i]: checkbox for i, checkbox in enumerate(checkbox_objects)}\n",
        "\n",
        "        ui = widgets.VBox(children=checkbox_objects) # 创建widget\n",
        "\n",
        "        selected_data = []\n",
        "        select_value = [] # 存储每个模型选择情况\n",
        "        url_list = [] # 地址列表\n",
        "        def select_data(**kwargs): # 每次点击按钮时都会执行\n",
        "            selected_data.clear()\n",
        "            select_value.clear()\n",
        "            for key in kwargs:\n",
        "                if kwargs[key] is True:\n",
        "                    selected_data.append(key)\n",
        "                    select_value.append(True)\n",
        "                else:\n",
        "                    select_value.append(False)\n",
        "\n",
        "            list = \"\"\n",
        "            for i in selected_data: # 已选择的模型列表(模型名称)\n",
        "                list = f\"{list}\\n- {i}\"\n",
        "            print(f\"已选择列表: {list}\")\n",
        "            j = 0\n",
        "            url_list.clear()\n",
        "            for i in select_value: # 返回的地址列表\n",
        "                if i is True:\n",
        "                    url_list.append(data[j][0])\n",
        "                j += 1\n",
        "\n",
        "        out = widgets.interactive_output(select_data, arg_dict)\n",
        "        ui.children = [*ui.children, out]\n",
        "        ui = widgets.Accordion(children=[ui,], titles=(name,))\n",
        "        #display(ui, out)\n",
        "        display(ui)\n",
        "        return url_list\n",
        "\n",
        "\n",
        "    def select_button(self, name, normal_value):\n",
        "        import ipywidgets as widgets\n",
        "        return widgets.Checkbox(\n",
        "            value=normal_value,\n",
        "            description=name,\n",
        "            disabled=False,\n",
        "            indent=False\n",
        "        )\n",
        "\n",
        "\n",
        "    def text_input(self, name, notice, normal_text=\"\"):\n",
        "        import ipywidgets as widgets\n",
        "        return widgets.Textarea(\n",
        "            value=normal_text,\n",
        "            placeholder=notice ,\n",
        "            description=name,\n",
        "            disabled=False\n",
        "        )\n",
        "\n",
        "\n",
        "    def dropdown(self, name, list, normal_value):\n",
        "        import ipywidgets as widgets\n",
        "        widgets.Dropdown(\n",
        "            options=list,\n",
        "            value=normal_value,\n",
        "            description=name,\n",
        "            disabled=False,\n",
        "        )\n",
        "\n",
        "\n",
        "\n",
        "# FOOOCUS\n",
        "class FOOOCUS(ARIA2, GIT, TUNNEL, MANAGER, ENV):\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "    tun = TUNNEL(WORKSPACE, WORKFOLDER, 7865)\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    # 下载大模型\n",
        "    def get_sd_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/checkpoints\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_sd_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_sd_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    # 下载lora模型\n",
        "    def get_lora_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/loras\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_lora_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_lora_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    # 下载配置文件\n",
        "    def install_config(self):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        echo(\"下载配置文件\")\n",
        "        self.aria2(\"https://github.com/licyk/term-sd/releases/download/archive/fooocus_config.json\", path + \"/presets\", \"custom.json\")\n",
        "        self.aria2(\"https://github.com/licyk/term-sd/releases/download/archive/fooocus_zh_cn.json\", path + \"/language\", \"zh.json\")\n",
        "\n",
        "\n",
        "    def install_config_colab(self):\n",
        "        import os\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        path_config = path + \"/config.txt\"\n",
        "        echo(\"下载路径配置文件\")\n",
        "        if os.path.exists(path_config):\n",
        "            !rm -rf \"{path_config}\"\n",
        "        self.aria2(\"https://github.com/licyk/term-sd/releases/download/archive/fooocus_path_config_colab.json\", path, \"config.txt\")\n",
        "\n",
        "\n",
        "    # 安装fooocus\n",
        "    def install(self, torch_ver, xformers_ver, sd, lora, use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE)\n",
        "        self.check_gpu()\n",
        "        self.prepare_env_depend(use_mirror)\n",
        "        self.clone(\"https://github.com/lllyasviel/Fooocus\", self.WORKSPACE)\n",
        "        os.chdir(f\"{self.WORKSPACE}/{self.WORKFOLDER}\")\n",
        "        self.prepare_torch(torch_ver, xformers_ver, use_mirror)\n",
        "        req_file = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/requirements_versions.txt\"\n",
        "        self.install_requirements(req_file, use_mirror)\n",
        "        self.install_config()\n",
        "        self.tcmalloc()\n",
        "        echo(\"下载模型\")\n",
        "        self.get_sd_model_from_list(sd)\n",
        "        self.get_lora_model_from_list(lora)\n",
        "\n",
        "\n",
        "    def update(self):\n",
        "        import os\n",
        "        fooocus_path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        self.pull(fooocus_path)\n",
        "\n",
        "\n",
        "\n",
        "# INVOKEAI\n",
        "class INVOKEAI(ARIA2, TUNNEL, MANAGER, ENV):\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "    tun = TUNNEL(WORKSPACE, WORKFOLDER, 9090)\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    def get_sd_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/checkpoint\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_sd_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_sd_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def get_lora_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/loras\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_lora_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_lora_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def get_embedding_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/embeddings\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_embedding_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_embedding_model(i, i.split(\"/\").pop())\n",
        "\n",
        "    def get_vae_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/models/vae\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_vae_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_vae_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def install(self, torch_ver, xformers_ver, sd, lora, vae, embedding, use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE)\n",
        "        self.check_gpu()\n",
        "        self.prepare_env_depend(use_mirror)\n",
        "        os.mkdir(f\"{self.WORKSPACE}/{self.WORKFOLDER}\")\n",
        "        os.chdir(f\"{self.WORKSPACE}/{self.WORKFOLDER}\")\n",
        "        self.prepare_torch(\"\", xformers_ver)\n",
        "        self.py_pkg_manager(\"invokeai\", \"install\", use_mirror)\n",
        "        self.tcmalloc()\n",
        "        echo(\"下载模型\")\n",
        "        self.get_sd_model_from_list(sd)\n",
        "        self.get_lora_model_from_list(lora)\n",
        "        self.get_vae_model_from_list(vae)\n",
        "        self.get_embedding_model_from_list(embedding)\n",
        "\n",
        "\n",
        "    def update(self):\n",
        "        echo(\"更新 InvokeAI\")\n",
        "        !pip install invokeai -U\n",
        "\n",
        "\n",
        "\n",
        "# SD_TRAINER\n",
        "class SD_TRAINER(ARIA2, GIT, TUNNEL, MANAGER, ENV):\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "    tun = TUNNEL(WORKSPACE, WORKFOLDER, 28000)\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    def get_sd_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-models\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_vae_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-models\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_sd_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_sd_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def get_vae_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_vae_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def install_kohya_requirements(self,use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-scripts\")\n",
        "        self.install_requirements(self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-scripts/requirements.txt\", use_mirror)\n",
        "        os.chdir(self.WORKSPACE + \"/\" + self.WORKFOLDER)\n",
        "\n",
        "\n",
        "    def install(self, torch_ver, xformers_ver, sd, vae, use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE)\n",
        "        self.check_gpu()\n",
        "        self.prepare_env_depend(use_mirror)\n",
        "        self.clone(\"https://github.com/Akegarasu/lora-scripts\", self.WORKSPACE)\n",
        "        os.chdir(f\"{self.WORKSPACE}/{self.WORKFOLDER}\")\n",
        "        self.prepare_torch(torch_ver, xformers_ver)\n",
        "        req_file = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/requirements.txt\"\n",
        "        # self.install_kohya_requirements(use_mirror)\n",
        "        self.install_requirements(req_file, use_mirror)\n",
        "        self.tcmalloc()\n",
        "        self.get_sd_model_from_list(sd)\n",
        "        self.get_vae_model_from_list(vae)\n",
        "\n",
        "\n",
        "    def update(self):\n",
        "        import os\n",
        "        sd_trainer_path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        self.pull(sd_trainer_path)\n",
        "\n",
        "\n",
        "    def get_core_ver(self):\n",
        "        sd_trainer_path =  self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        print(self.log(sd_trainer_path))\n",
        "\n",
        "\n",
        "    def set_core_ver(self, commit):\n",
        "        sd_trainer_path =  self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        self.checkout(sd_trainer_path, commit)\n",
        "\n",
        "\n",
        "    def show_ver(self):\n",
        "        import os\n",
        "        sd_trainer_path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        echo(\"SD Trainer 版本:\")\n",
        "        print(self.git_show_ver(sd_trainer_path))\n",
        "\n",
        "\n",
        "# KOHYA GUI\n",
        "class KOHYA_GUI(ARIA2, GIT, TUNNEL, MANAGER, ENV):\n",
        "    WORKSPACE = \"\"\n",
        "    WORKFOLDER = \"\"\n",
        "\n",
        "    tun = TUNNEL(WORKSPACE, WORKFOLDER, 7860)\n",
        "\n",
        "    def __init__(self, workspace, workfolder) -> None:\n",
        "        self.WORKSPACE = workspace\n",
        "        self.WORKFOLDER = workfolder\n",
        "\n",
        "\n",
        "    def get_sd_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-models\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_vae_model(self, url, filename = None):\n",
        "        path = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-models\"\n",
        "        filename = url.split(\"/\").pop() if filename is None else filename\n",
        "        super().aria2(url, path, filename)\n",
        "\n",
        "\n",
        "    def get_sd_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_sd_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def get_vae_model_from_list(self, list):\n",
        "        for i in list:\n",
        "            if i != \"\":\n",
        "                self.get_vae_model(i, i.split(\"/\").pop())\n",
        "\n",
        "\n",
        "    def install_kohya_requirements(self,use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-scripts\")\n",
        "        self.install_requirements(self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/sd-scripts/requirements.txt\", use_mirror)\n",
        "        os.chdir(self.WORKSPACE + \"/\" + self.WORKFOLDER)\n",
        "\n",
        "\n",
        "    def install(self, torch_ver, xformers_ver, sd, vae, use_mirror):\n",
        "        import os\n",
        "        os.chdir(self.WORKSPACE)\n",
        "        self.check_gpu()\n",
        "        self.prepare_env_depend(use_mirror)\n",
        "        self.clone(\"https://github.com/bmaltais/kohya_ss\", self.WORKSPACE)\n",
        "        os.chdir(f\"{self.WORKSPACE}/{self.WORKFOLDER}\")\n",
        "        self.prepare_torch(torch_ver, xformers_ver)\n",
        "        req_file = self.WORKSPACE + \"/\" + self.WORKFOLDER + \"/requirements.txt\"\n",
        "        # self.install_kohya_requirements(use_mirror)\n",
        "        self.install_requirements(req_file, use_mirror)\n",
        "        self.tcmalloc()\n",
        "        self.get_sd_model_from_list(sd)\n",
        "        self.get_vae_model_from_list(vae)\n",
        "\n",
        "\n",
        "    def update(self):\n",
        "        import os\n",
        "        kohya_gui_path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        self.pull(kohya_gui_path)\n",
        "\n",
        "\n",
        "    def get_core_ver(self):\n",
        "        kohya_gui_path =  self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        print(self.log(kohya_gui_path))\n",
        "\n",
        "\n",
        "    def set_core_ver(self, commit):\n",
        "        kohya_gui_path =  self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        self.checkout(kohya_gui_path, commit)\n",
        "\n",
        "\n",
        "    def show_ver(self):\n",
        "        import os\n",
        "        kohya_gui_path = self.WORKSPACE + \"/\" + self.WORKFOLDER\n",
        "        echo(\"Kohya_GUI 版本:\")\n",
        "        print(self.git_show_ver(kohya_gui_path))\n",
        "\n",
        "\n",
        "echo(\"初始化功能完成\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "editable": true,
        "id": "Ry2HYOEE_yd6",
        "outputId": "087427b7-5c71-45c2-de3f-db49b8892c5c",
        "tags": []
      },
      "outputs": [],
      "source": [
        "#@title 👇 参数配置\n",
        "try:\n",
        "    i = INIT_CONFIG\n",
        "    echo(\"尝试安装 ipywidgets 组件\")\n",
        "    !pip install ipywidgets -qq\n",
        "    from IPython.display import clear_output\n",
        "    clear_output(wait=False)\n",
        "    INIT_CONFIG_1 = 1\n",
        "except:\n",
        "    raise Exception(\"未初始化功能\")\n",
        "\n",
        "import ipywidgets as widgets\n",
        "\n",
        "WEBUI = \"\"\n",
        "WORKSPACE = \"\"\n",
        "WORKFOLDER = \"\"\n",
        "USE_MIRROR = False\n",
        "USE_NGROK = True\n",
        "NGROK_TOKEN = \"\"\n",
        "USE_CLOUDFLARE = True\n",
        "USE_REMOTE_MOE = True\n",
        "USE_LOCALHOST_RUN = True\n",
        "USE_GRADIO_SHARE = False\n",
        "TORCH_VER = \"\"\n",
        "XFORMERS_VER = \"\"\n",
        "GITHUB_MIRROR = [\n",
        "    \"https://ghproxy.net/https://github.com/term_sd_git_user/term_sd_git_repo\",\n",
        "    \"https://mirror.ghproxy.com/https://github.com/term_sd_git_user/term_sd_git_repo\",\n",
        "    \"https://gh-proxy.com/https://github.com/term_sd_git_user/term_sd_git_repo\",\n",
        "    \"https://ghps.cc/https://github.com/term_sd_git_user/term_sd_git_repo\",\n",
        "    \"https://gh.idayer.com/https://github.com/term_sd_git_user/term_sd_git_repo\",\n",
        "    \"https://gitclone.com/github.com/term_sd_git_user/term_sd_git_repo\"\n",
        "]\n",
        "HUGGINGFACE_MIRROR = \"https://hf-mirror.com\"\n",
        "sd_model = [\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/v1-5-pruned-emaonly.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/animefull-final-pruned.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/Counterfeit-V3.0_fp16.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/cetusMix_Whalefall2.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/cuteyukimixAdorable_neochapter3.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/ekmix-pastel-fp16-no-ema.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/ex2K_sse2.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/kohakuV5_rev2.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/meinamix_meinaV11.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/oukaStar_10.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/pastelMixStylizedAnime_pastelMixPrunedFP16.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/rabbit_v6.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/sweetSugarSyndrome_rev15.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/AnythingV5Ink_ink.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/bartstyledbBlueArchiveArtStyleFineTunedModel_v10.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/meinapastel_v6Pastel.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/qteamixQ_omegaFp16.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sd_1.5/tmndMix_tmndMixSPRAINBOW.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/sd_xl_base_1.0_0.9vae.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/animagine-xl-3.0.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/AnythingXL_xl.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/abyssorangeXLElse_v10.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/animaPencilXL_v200.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/animagine-xl-3.1.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/heartOfAppleXL_v20.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/baxlBartstylexlBlueArchiveFlatCelluloid_xlv1.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/kohaku-xl-delta-rev1.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/kohakuXLEpsilon_rev1.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/kohaku-xl-epsilon-rev3.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/kohaku-xl-zeta.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/nekorayxl_v06W3.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/CounterfeitXL-V1.0.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-model/resolve/main/sdxl_1.0/ponyDiffusionV6XL_v6StartWithThisOne.safetensors\", 0]\n",
        "]\n",
        "lora = [\n",
        "    [\"https://huggingface.co/licyk/sd-lora/resolve/main/sdxl/style/AnimagineXLV3_Style_Difference_AnimeFace.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-lora/resolve/main/sdxl/style/AnimagineXLV3_Style_Difference_Saturation.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-lora/resolve/main/sdxl/style/AnimagineXLV3_Style_Difference_EdgeEmphasys.safetensors\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-lora/resolve/main/sdxl/style/AnimagineXLV3_Style_Difference_bodyshadow.safetensors\", 0],\n",
        "    [\"https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/resolve/main/sd_xl_offset_example-lora_1.0.safetensors\", 0]\n",
        "]\n",
        "embedding = [\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/EasyNegative.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/EasyNegativeV2.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/bad-artist-anime.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/bad-artist.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/bad-hands-5.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/bad-image-v2-39000.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/bad_prompt_version2.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/ng_deepnegative_v1_75t.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-embeddings/resolve/main/sd_1.5/verybadimagenegative_v1.3.pt\", 1]\n",
        "]\n",
        "vae = [\n",
        "    [\"https://huggingface.co/licyk/sd-vae/resolve/main/sd_1.5/vae-ft-ema-560000-ema-pruned.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-vae/resolve/main/sd_1.5/vae-ft-mse-840000-ema-pruned.safetensors\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-vae/resolve/main/sdxl_1.0/sdxl_fp16_fix_vae.safetensors\", 1]\n",
        "]\n",
        "vae_approx = [\n",
        "    [\"https://huggingface.co/licyk/sd-vae/resolve/main/vae-approx/model.pt\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-vae/resolve/main/vae-approx/vaeapprox-sdxl.pt\", 1]\n",
        "]\n",
        "upscale = [\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/ESRGAN/4x-UltraSharp.pth\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/ESRGAN/ESRGAN_4x.pth\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/ESRGAN/4x_NMKD-Superscale-SP_178000_G.pth\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/RealESRGAN/RealESRGAN_x4plus.pth\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/RealESRGAN/RealESRGAN_x4plus_anime_6B.pth\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/DAT/DAT_x2.pth\", 0],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/DAT/DAT_x3.pth\", 1],\n",
        "    [\"https://huggingface.co/licyk/sd-upscaler-models/resolve/main/DAT/DAT_x4.pth\", 1]\n",
        "]\n",
        "\n",
        "WEBUI_LIST = [\"fooocus\", \"invokeai\", \"sd_trainer\", \"kohya_gui\"]\n",
        "\n",
        "manager = MANAGER(WORKSPACE, WORKFOLDER)\n",
        "gi = GIT(WORKSPACE, WORKFOLDER)\n",
        "\n",
        "workspace_state = widgets.Textarea(value=\"/content\", placeholder=\"请输入工作区路径\", description=\"工作区路径: \", disabled=False)\n",
        "webui_state = widgets.Dropdown(options=WEBUI_LIST, value=\"fooocus\", description=\"使用的 WebUI: \", disabled=False)\n",
        "torch_ver_state = widgets.Textarea(value=\"torch==2.2.1+cu121 torchvision==0.17.1+cu121 torchaudio==2.2.1+cu121\", placeholder=\"请填写 PyTorch 版本\", description=\"PyTorch 版本: \", disabled=False)\n",
        "xformers_ver_state = widgets.Textarea(value=\"xformers==0.0.25\", placeholder=\"请填写 xFormers 版本\", description=\"xFormers 版本: \", disabled=False)\n",
        "use_mirror_state = widgets.Checkbox(value=False, description=\"使用镜像源\", disabled=False)\n",
        "is_colab_state = widgets.Checkbox(value=True, description=\"使用 Colab 环境\", disabled=False)\n",
        "use_ngrok_state = widgets.Checkbox(value=False, description=\"使用 Ngrok 内网穿透\", disabled=False)\n",
        "ngrok_token_state = widgets.Textarea(value=\"\", placeholder=\"请填写 Ngrok Token（可在 Ngrok 官网获取）\", description=\"Ngrok Token: \", disabled=False)\n",
        "use_cloudflare_state = widgets.Checkbox(value=False, description=\"使用 CloudFlare 内网穿透\", disabled=False)\n",
        "use_remote_moe_state = widgets.Checkbox(value=True, description=\"使用 remote.moe 内网穿透\", disabled=False)\n",
        "use_localhost_run_state = widgets.Checkbox(value=True, description=\"使用 localhost.run 内网穿透\", disabled=False)\n",
        "use_gradio_share_state = widgets.Checkbox(value=False, description=\"使用 Gradio 内网穿透\", disabled=False)\n",
        "display(workspace_state, webui_state, torch_ver_state, xformers_ver_state, use_mirror_state, use_ngrok_state, ngrok_token_state, use_cloudflare_state, use_remote_moe_state, use_localhost_run_state, use_gradio_share_state)\n",
        "\n",
        "\n",
        "sd_model_list = manager.select_list(sd_model,\"Stable Diffusion 模型\")\n",
        "lora_list = manager.select_list(lora, \"LoRA 模型\")\n",
        "embedding_list = manager.select_list(embedding, \"Embedding 模型\")\n",
        "vae_list = manager.select_list(vae, \"VAE 模型\")\n",
        "vae_approx_list = manager.select_list(vae_approx, \"VAE-approx 模型\")\n",
        "upscale_list = manager.select_list(upscale, \"放大模型\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "f3MUpZmT_yd8"
      },
      "outputs": [],
      "source": [
        "#@title 👇 应用参数配置\n",
        "try:\n",
        "    i = INIT_CONFIG_1\n",
        "    INIT_CONFIG_1 = 1\n",
        "    INIT_CONFIG_2 = 1\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"参数配置\\\"单元\")\n",
        "\n",
        "import os\n",
        "os.chdir(WORKSPACE)\n",
        "WORKSPACE = workspace_state.value.rstrip(\"/\").rstrip(\"\\\\\")\n",
        "WEBUI = webui_state.value\n",
        "TORCH_VER = torch_ver_state.value\n",
        "XFORMERS_VER = xformers_ver_state.value\n",
        "USE_MIRROR = use_mirror_state.value\n",
        "IS_COLAB = is_colab_state.value\n",
        "USE_NGROK = use_ngrok_state.value\n",
        "NGROK_TOKEN = ngrok_token_state.value\n",
        "USE_CLOUDFLARE = use_cloudflare_state.value\n",
        "USE_REMOTE_MOE = use_remote_moe_state.value\n",
        "USE_LOCALHOST_RUN = use_localhost_run_state.value\n",
        "USE_GRADIO_SHARE = use_gradio_share_state.value\n",
        "\n",
        "if WORKSPACE != \"\":\n",
        "    if WEBUI == \"fooocus\":\n",
        "        WORKFOLDER = \"Fooocus\"\n",
        "        fooocus = FOOOCUS(WORKSPACE, WORKFOLDER)\n",
        "    elif WEBUI == \"invokeai\":\n",
        "        WORKFOLDER = \"InvokeAI\"\n",
        "        invokeai = INVOKEAI(WORKSPACE, WORKFOLDER)\n",
        "    elif WEBUI == \"sd_trainer\":\n",
        "        WORKFOLDER = \"lora-scripts\"\n",
        "        sd_trainer = SD_TRAINER(WORKSPACE, WORKFOLDER)\n",
        "    elif WEBUI == \"kohya_gui\":\n",
        "        WORKFOLDER = \"kohya_ss\"\n",
        "        kohya_gui = KOHYA_GUI(WORKSPACE, WORKFOLDER)\n",
        "else:\n",
        "    raise Exception(\"未填写工作区路径\")\n",
        "\n",
        "manager = MANAGER(WORKSPACE, WORKFOLDER)\n",
        "\n",
        "if USE_MIRROR:\n",
        "    sd_model = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, sd_model_list)\n",
        "    lora = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, lora_list)\n",
        "    embedding = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, embedding_list)\n",
        "    vae = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, vae_list)\n",
        "    vae_approx = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, vae_approx_list)\n",
        "    upscale = manager.hf_link_to_mirror_link(HUGGINGFACE_MIRROR, upscale_list)\n",
        "    manager.set_huggingface_mirror(HUGGINGFACE_MIRROR)\n",
        "    gi.set_github_mirror(GITHUB_MIRROR)\n",
        "echo(\"参数设置完成\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "0wKZt0Ca_yd9"
      },
      "outputs": [],
      "source": [
        "#@title 👇 安装\n",
        "try:\n",
        "    i = INIT_CONFIG_2\n",
        "    INIT_CONFIG_2 = 1\n",
        "    INIT_CONFIG_3 = 1\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"参数设置\\\"单元\")\n",
        "\n",
        "import os\n",
        "os.chdir(WORKSPACE)\n",
        "echo(f\"开始安装 {WEBUI}\")\n",
        "if WEBUI == \"fooocus\":\n",
        "    fooocus.install(TORCH_VER, XFORMERS_VER, sd_model_list, lora_list, USE_MIRROR)\n",
        "    if IS_COLAB is True:\n",
        "        fooocus.tcmalloc_colab()\n",
        "        fooocus.install_config_colab()\n",
        "elif WEBUI == \"invokeai\":\n",
        "    invokeai.install(TORCH_VER, XFORMERS_VER, sd_model_list, lora_list, vae_list, embedding_list, USE_MIRROR)\n",
        "    if IS_COLAB is True:\n",
        "        fooocus.tcmalloc_colab()\n",
        "elif WEBUI == \"sd_trainer\":\n",
        "    sd_trainer.install(TORCH_VER, XFORMERS_VER, sd_model_list, vae_list, USE_MIRROR)\n",
        "    if IS_COLAB is True:\n",
        "        sd_trainer.tcmalloc_colab()\n",
        "elif WEBUI == \"kohya_gui\":\n",
        "    kohya_gui.install(TORCH_VER, XFORMERS_VER, sd_model_list, vae_list, USE_MIRROR)\n",
        "    if IS_COLAB is True:\n",
        "        kohya_gui.tcmalloc_colab()\n",
        "manager.clear_up(False)\n",
        "echo(f\"{WEBUI} 安装完成\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "iKZbtmP1_yd_"
      },
      "outputs": [],
      "source": [
        "#@title 👇 启动\n",
        "try:\n",
        "    i = INIT_CONFIG_3\n",
        "    INIT_CONFIG_3 = 1\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"安装\\\"单元\")\n",
        "\n",
        "import os\n",
        "os.chdir(WORKSPACE + \"/\" + WORKFOLDER)\n",
        "echo(f\"启动 {WEBUI}\")\n",
        "if WEBUI == \"fooocus\":\n",
        "    fooocus.tun.start(ngrok=USE_NGROK, ngrok_token=NGROK_TOKEN, cloudflare=USE_CLOUDFLARE, remote_moe=USE_REMOTE_MOE, localhost_run=USE_LOCALHOST_RUN, gradio=False)\n",
        "    if USE_GRADIO_SHARE:\n",
        "        !python \"{WORKSPACE}\"/Fooocus/launch.py --preset custom --language zh --disable-offload-from-vram --async-cuda-allocation --share\n",
        "    else:\n",
        "        !python \"{WORKSPACE}\"/Fooocus/launch.py --preset custom --language zh --disable-offload-from-vram --async-cuda-allocation\n",
        "elif WEBUI == \"invokeai\":\n",
        "    invokeai.tun.start(ngrok=USE_NGROK, ngrok_token=NGROK_TOKEN, cloudflare=USE_CLOUDFLARE, remote_moe=USE_REMOTE_MOE, localhost_run=USE_LOCALHOST_RUN, gradio=False)\n",
        "    if USE_GRADIO_SHARE:\n",
        "    !invokeai-web --root \"{WORKSPACE}\"/InvokeAI/invokeai\n",
        "elif WEBUI == \"sd_trainer\":\n",
        "    sd_trainer.tun.start(ngrok=USE_NGROK, ngrok_token=NGROK_TOKEN, cloudflare=USE_CLOUDFLARE, remote_moe=USE_REMOTE_MOE, localhost_run=USE_LOCALHOST_RUN, gradio=False)\n",
        "    !python \"{WORKSPACE}\"/lora-scripts/gui.py\n",
        "elif WEBUI == \"kohya_gui\":\n",
        "    kohya_gui.tun.start(ngrok=USE_NGROK, ngrok_token=NGROK_TOKEN, cloudflare=USE_CLOUDFLARE, remote_moe=USE_REMOTE_MOE, localhost_run=USE_LOCALHOST_RUN, gradio=False)\n",
        "    if USE_GRADIO_SHARE:\n",
        "        !python \"{WORKSPACE}\"/kohya_ss/kohya_gui.py --language zh-CN --share\n",
        "    else:\n",
        "        !python \"{WORKSPACE}\"/kohya_ss/kohya_gui.py --language zh-CN\n",
        "manager.clear_up(False)\n",
        "echo(f\"{WEBUI} 已关闭\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C7GxnRN4_yd_"
      },
      "source": [
        "##✨ 其他功能"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "25Gcy5jO_yeB"
      },
      "outputs": [],
      "source": [
        "#@title 👇 自定义模型 / 扩展下载配置\n",
        "try:\n",
        "    i = INIT_CONFIG_3\n",
        "    INIT_CONFIG_3 = 1\n",
        "    INIT_CONFIG_4 = 1\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"安装\\\"单元\")\n",
        "\n",
        "import ipywidgets as widgets\n",
        "\n",
        "model_ = widgets.Textarea(\n",
        "    value=\"\",\n",
        "    placeholder='请填写模型 / 扩展下载链接',\n",
        "    description='模型 / 扩展下载链接: ',\n",
        "    disabled=False\n",
        ")\n",
        "\n",
        "model_name_ = widgets.Textarea(\n",
        "    value=\"\",\n",
        "    placeholder='请填写模型名称',\n",
        "    description='模型名称: ',\n",
        "    disabled=False\n",
        ")\n",
        "\n",
        "model_type_ = widgets.Dropdown(\n",
        "    options=[(\"Stable Diffusion 模型（大模型）\", \"sd\"),\n",
        "             (\"LoRA 模型\", \"lora\"),\n",
        "             (\"Emebdding 模型\", \"embedding\"),\n",
        "             (\"VAE 模型\", \"vae\"),\n",
        "             (\"VAE-approx 模型\", \"vae-approx\"),\n",
        "             (\"放大模型\", \"upscale\"),\n",
        "             (\"ControlNet 模型\", \"controlnet\"),\n",
        "             (\"SD WebUI 扩展\", \"extension\"),\n",
        "             (\"ComfyUI 扩展\", \"custom_node\")\n",
        "             ],\n",
        "    value=\"sd\",\n",
        "    description='模型 / 扩展种类',\n",
        ")\n",
        "\n",
        "display(model_, model_name_, model_type_)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "33RPATJT_yeB"
      },
      "outputs": [],
      "source": [
        "#@title 👇 自定义模型 / 扩展下载\n",
        "try:\n",
        "    i = INIT_CONFIG_4\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"自定义模型 / 扩展下载配置\\\"单元\")\n",
        "\n",
        "model = model_.value\n",
        "model_name = model_name_.value\n",
        "model_type = model_type_.value\n",
        "\n",
        "if model == \"\" and model_name == \"\":\n",
        "    raise Exception(\"未填写模型 / 扩展链接或者模型名称\")\n",
        "\n",
        "\n",
        "if WEBUI == \"invokeai\":\n",
        "    if model_type == \"sd\":\n",
        "        invokeai.get_sd_model(model, model_name)\n",
        "    if model_type == \"lora\":\n",
        "        invokeai.get_lora_model(model, model_name)\n",
        "    if model_type == \"embedding\":\n",
        "        invokeai.get_embedding_model(model, model_name)\n",
        "    if model_type == \"vae\":\n",
        "        invokeai.get_vae_model(model, model_name)\n",
        "elif WEBUI == \"fooocus\":\n",
        "    if model_type == \"sd\":\n",
        "        fooocus.get_sd_model(model, model_name)\n",
        "    if model_type == \"lora\":\n",
        "        fooocus.get_lora_model(model, model_name)\n",
        "elif WEBUI == \"sd_trainer\":\n",
        "    if model_type == \"sd\":\n",
        "        sd_trainer.get_sd_model(model, model_name)\n",
        "    if model_type == \"vae\":\n",
        "        sd_trainer.get_vae_model(model, model_name)\n",
        "elif WEBUI == \"kohya_gui\":\n",
        "    if model_type == \"sd\":\n",
        "        kohya_gui.get_sd_model(model, model_name)\n",
        "    if model_type == \"vae\":\n",
        "        kohya_gui.get_vae_model(model, model_name)\n",
        "else:\n",
        "    raise Exception(f\"未知软件类型 {WEBUI}\")\n",
        "\n",
        "echo(f\"{WEBUI} 模型文件扩展下载完成\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "UT_eaCug_yeB"
      },
      "outputs": [],
      "source": [
        "#@title 👇 更新\n",
        "try:\n",
        "    i = INIT_CONFIG_3\n",
        "    INIT_CONFIG_3 = 1\n",
        "except:\n",
        "    raise Exception(\"未运行\\\"安装\\\"单元\")\n",
        "\n",
        "import os\n",
        "os.chdir(WORKSPACE + \"/\" + WORKFOLDER)\n",
        "echo(f\"启动 {WEBUI}\")\n",
        "if WEBUI == \"fooocus\":\n",
        "    fooocus.update()\n",
        "elif WEBUI == \"invokeai\":\n",
        "    invokeai.update()\n",
        "elif WEBUI == \"sd_trainer\":\n",
        "    sd_trainer.update()\n",
        "elif WEBUI == \"kohya_gui\":\n",
        "    kohya_gui.update()\n",
        "echo(f\"更新 {WEBUI} 完成\")"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "C7GxnRN4_yd_"
      ],
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3 (ipykernel)",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.11"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
